<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Payment
 * @subpackage Gateway
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id:  $
 */

/**
 * @see Zend_Loader
 */
require_once 'Zend/Loader.php';


/**
 * Class for online Ecommerce charging/payments
 *
 * @category   Zend
 * @package    Zend_Payment
 * @subpackage Gateway
 * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id:  $
 */
abstract class Tavs_Payment_Gateway_Abstract
{
	/**
     * Array with all options, each gateway can have own additional options
     *
     * @var array
     */
	protected $_fields = array();

	/**
     * Required options per gateways, things such as suplier, merchant account id
     * email addresess
     *
     * Other:
     * 		 'gatewayNamespace' => custom namespace for a gateway
     *
     * @var array
     */
	protected $options = array(

	'exceptions' => false, // throw exceptions?
	'gatewayNamespace' => null,
	'certificate' => false, // paypal related
	'PDT' => false, // paypal related
	'debug' => false, // debug
	);

	/**
     * array containing reposnse from the gateway provider
     *
     * @var array
     */
	protected $_response = array();

	/**
     * Error code holder returned by the gateway provider
     *
     * @var int
     */
	protected $_errorcode = null;


	/**
     * Error string returned by the gateway provider
     *
     * @var string
     */
	protected $_error_string = null;

	/**
	 * Http client object
	 *
	 * @var object
	 */
	protected $client;

	/**
	 * Throw exceptions?
	 *
	 */
	const THROW_EXCEPTIONS = false;

	/**
     * Payment result codes
     */
	const APPROVED = 100; // payment approved
	const DECLINED = 101; // payment declined
	const OTHER = 102; // other
	const FRAUD = 103; // fraud detected
	const DUPLICATE = 104; // duplicate
	const REVIEW = 105; // marked for reivew
	const CCNUMBER_INVALID = 106;
	const CVV_INVALID = 107;
	const CCNUMBER_MISSING = 108;
	const CCNUMBER_EXPIRED = 109;
	const TRANSACTION_TYPE_INVALID = 110;
	const TRANSACTION_CODE_INVALID = 111;
	const CREDIT_TYPE_NOT_SUPPORTED = 112;
	const CURRENCY_NOT_SUPPORTED = 113;
	const GATEWAY_INACCESSIBLE = 114;
	const FILL_ALL_FIELDS = 115;
	const MISSING_REQ_OPTIONS = 116;

	/**
     * Payment type codes
     *
     */
	const Payment_Type_Sale = 'Sale';
	const Payment_Type_Auth = 'Authorization';
	const Payment_Type_Order = 'Order';

	/**
     * Constructor.
     *
     * $options is an array of key/value pairs or an instance of Zend_Config
     * containing configuration options.
     *
     * @param  array|Zend_Config $options An array or instance of Zend_Config having configuration data
     * @throws Tavs_Payment_Exception
     */
	public function __construct($options, Zend_Http_Client $client=null)
	{
		/*
		* Verify that gateway parameters are in an array.
		*/
		if (!is_array($options))
		{
			/*
			* Convert Zend_Config argument to a plain array.
			*/
			if ($options instanceof Zend_Config)
			{
				$options = $options->toArray();
			}
			else
			{
				/**
                 * @see Tavs_Payment_Exception
                 */
				require_once 'Tavs/Payment/Exception.php';
				throw new Tavs_Payment_Exception('Gateway parameters must be in an array or a Zend_Config object');
			}
		}

		# Http Client
		if($client !== null)
		{
			$this->client = $client;
		}
		else
		{
			# Load Http Client
			$this->client = new Zend_Http_Client();

			# Config options
			$this->client->setConfig(array(
			'maxredirects' => 0,
			'timeout'      => 30));
		}

		# Pass in the config to the array holder
		$this->options = $options;

		$this->checkRequiredOptions($options);

	}

	/**
     * Get a field from the fields array
     *
     * @param string|boolean|array|int $name
     */
	public function getField($name)
	{
		return array_key_exists($name, $this->_fields) ? $this->_fields[$name] : null;
	}

	/**
     * Add a key=>value pair to the fields stack
     *
     * @param string $name
     * @param string|boolean|array|int $value
     * @return object
     */
	public function setField($name, $value)
	{
		$this->_fields[$name] = $value;
		return $this;
	}

	/**
     * Set multiple fields
     *
     * @param array $fields
     */
	public function setFields(array $fields)
	{
		if( is_array($fields) && count($fields) )
		{
			foreach($fields as $key => $value)
			{
				$this->setField($key, $value);
			}
		}
	}

	/**
     * Magic method to set a field
     *
     * @param string $name
     * @param string|boolean|array|int $value
     * @return $value
     */
	public function __set($name, $value)
	{
		return $this->setField($name, $value);
	}

	/**
     * Magic method to get a value of a fied by it's name
     *
     * @param  string $name
     */
	public function __get($name)
	{
		return $this->getField($name);
	}

	/**
     * Returns the configuration variables in this gateway.
     * Or a single config var if the $value passed
     *
     * @param string $value
     * @return array|string on success exception on failure
     */
	public function getConfig($value=null)
	{
		if($value)
		{
			if(array_key_exists($value, $this->options))
			{
				return $this->options[$value];
			}

			throw new Tavs_Payment_Gateway_Exception("The value {$value} was not found in the class config array");
		}

		return $this->options;
	}

	/**
	 * Set a config key=>value
	 *
	 * @param string $key
	 * @param string $value
	 * @return object
	 */
	protected function setConfig($key, $value)
	{
		$this->options[$key] = $value;
		return $this;
	}

	/**
	 * Throw exception on failure
	 *
	 * @param string $message
	 * @param int $code
	 * @throws Tavs_Payment_Gateway_Exception
	 */
	protected function throwException($message, $code)
	{
		/* Load the exception class */
		require_once('Tavs/Payment/Gateway/Exception.php');
		throw new Tavs_Payment_Gateway_Exception($message, $code);
	}

	/**
     * Was there any errors returned?
     *
     * @return boolean
     */
	public function _hasError()
	{
		return $this->_error_string ? true : false;
	}

	/**
     * Return the error string if any
     *
     * @return string
     */
	public function _getError()
	{
		return $this->_error_string;
	}

	/**
     * Return the error string if any
     *
     * @return string
     */
	public function _getErrorCode()
	{
		return $this->_errorcode ? $this->_errorcode : null;
	}


	/**
     * returns ture/false if there is any response from
     * the gateway provider
     *
     * @return boolean
     */
	public function _hasResponse()
	{
		return $this->_response ? true : false;
	}

	/**
     * Return the response array
     *
     * @return array
     */
	public function _getResponse()
	{
		return $this->_response;
	}

	/**
     * Return the array of fields
     *
     * @return array
     */
	public function _getFields()
	{
		return $this->_fields;
	}

	/**
	 * Toggle test mode
	 *
	 * @param bool $flag
	 */
	public function toggleTestMode($flag)
	{
		if($flag !== null)
		{
			$this->options['debug'] = (bool) $flag;
		}
	}

	/**
	 * Get response
	 *
	 */
	public function getResponse()
	{
		return $this->_response;
	}

	/**
     * Abstract Methods
     */

	/**
	 * Transaction failed
	 *
	 *
	 * @param array $params
	 * @return boolean
	 */
	abstract function isFailed( array $params=array() );

	/**
	 * Was the transaction successful
	 *
	 *
	 * @param array $params
	 * @return boolean
	 */
	abstract function isSuccess( array $params=array() );

}